package ly.count.android.sdk;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class ModuleDeviceIdTests {

    @Before
    public void setUp() {
        Countly.sharedInstance().halt();
        TestUtils.getCountlyStore().clear();
    }

    @After
    public void tearDown() {
        TestUtils.getCountlyStore().clear();
    }

    /**
     * "setID" with custom device id
     * - validate that device id is developer supplied
     * - set same id and validate that it is not set
     */
    @Test
    public void setID_sameCustom() {
        Countly countly = new Countly().init(TestUtils.createBaseConfig(TestUtils.commonDeviceId)); // custom id provided
        validateDeviceIdDeveloperSupplied(TestUtils.commonDeviceId, countly);

        countly.deviceId().setID(TestUtils.commonDeviceId);
        validateDeviceIdDeveloperSupplied(TestUtils.commonDeviceId, countly);
    }

    /**
     * "setID" with custom device id
     * - validate that device id is developer supplied
     * - set new id and validate that it is set
     */
    @Test
    public void setID_custom() {
        Countly countly = new Countly().init(TestUtils.createBaseConfig(TestUtils.commonDeviceId)); // custom id provided
        validateDeviceIdDeveloperSupplied(TestUtils.commonDeviceId, countly); // validate id exist and developer supplied

        String newId = "NEW_ID";
        countly.deviceId().setID(newId);
        validateDeviceIdDeveloperSupplied(newId, countly);
    }

    /**
     * "setID"
     * - Validate that device id is generated by the sdk
     * - Set a new id and validate that it is set
     * - Set null and validate that it is not changed
     * - Set empty and validate that it is not changed
     * - Set the same id and validate that it is not changed
     */
    @Test
    public void setID() {
        Countly countly = new Countly().init(TestUtils.createBaseConfig((String) null)); // no custom id provided
        validateDeviceIdIsSdkGenerated(countly); // validate id exist and sdk generated

        String newId = "NEW_ID";
        countly.deviceId().setID(newId);
        validateDeviceIdDeveloperSupplied(newId, countly);

        countly.deviceId().setID(null);
        validateDeviceIdDeveloperSupplied(newId, countly);

        countly.deviceId().setID("");
        validateDeviceIdDeveloperSupplied(newId, countly);

        countly.deviceId().setID(countly.deviceId().getID());
        validateDeviceIdDeveloperSupplied(newId, countly);
    }

    private void validateDeviceIdDeveloperSupplied(String expectedDeviceId, Countly countly) {
        Assert.assertEquals(expectedDeviceId, countly.deviceId().getID());
        Assert.assertEquals(DeviceIdType.DEVELOPER_SUPPLIED, countly.deviceId().getType());
    }

    private void validateDeviceIdIsSdkGenerated(Countly countly) {
        String deviceId = countly.deviceId().getID();
        try {
            Assert.assertTrue(validateDeviceIDIsAndroidID(deviceId));
            Assert.assertEquals(DeviceIdType.OPEN_UDID, countly.deviceId().getType());
        } catch (IllegalArgumentException e) {
            Assert.fail("Device id is not a valid OPEN_UDID");
        }
    }

    /**
     * Validates that the device id is a valid UUID and starts with "CLY_"
     */
    private boolean validateDeviceIDIsAndroidID(String androidId) {
        // Check if androidId is null or empty
        if (androidId == null || androidId.isEmpty()) {
            return false;
        }

        // Check if androidId is a known invalid value
        if (androidId.equals("9774d56d682e549c") || androidId.equalsIgnoreCase("unknown")) {
            return false;
        }

        // Check if androidId is a valid hexadecimal value
        /*try { TODO why this is failing?
            Long.parseLong(androidId, 16);
        } catch (NumberFormatException e) {
            return false;
        }*/

        return true;
    }
}
